// simple example
#include <sstream>
#include "../croweb.h"

class ExampleLogHandler: public crow::ILogHandler
{
public:
    ExampleLogHandler() = default;
    virtual ~ExampleLogHandler() = default;
    void log(std::string message, crow::LogLevel level) override
    {
        std::cerr << "ExampleLogHandler -> " << message << "\n";
    }
};

struct ExampleMiddleware
{
    std::string message;

    ExampleMiddleware()
    {
        message = "example";
    }

    void setMessage(std::string newMsg)
    {
        message = newMsg;
    }

    struct context
    {
    };

    void before_handle(crow::request& req, crow::response& res, context& ctx)
    {
        CROW_LOG_DEBUG << "Middleware Before: " << message;
    }

    void after_handle(crow::request& req, crow::response& res, context& ctx)
    {
        CROW_LOG_DEBUG << "Middleware After: " << message;
    }
};

int main(int argc, char* argv[])
{
    crow::App<ExampleMiddleware> app;

    CROW_ROUTE(app, "/").name("hello")([] {
        return "Hello World!";
    });

    CROW_ROUTE(app, "/about")([]() {
        return "About Crow example.";
    });

    // simple json response
    CROW_ROUTE(app, "/json")([] {
        crow::json::wvalue x;
        x["message"] = "Hello, World!";
        return x;
    });

    CROW_ROUTE(app, "/hello/<int>")([](int count) {
        if (count > 100)
        return crow::response(400);
        std::ostringstream os;
        os << count << " bottles of beer!";
        return crow::response(os.str());
    });

    CROW_ROUTE(app, "/add/<int>/<int>")([](const crow::request& req, crow::response& res, int a, int b) {
        std::ostringstream os;
        os << a + b;
        res.write(os.str());
        res.end();
    });

    // more json example
    CROW_ROUTE(app, "/add_json")([](const crow::request& req) {
        auto x = crow::json::load(req.body);
        if (!x)
        return crow::response(400);
        int sum = x["a"].i()+x["b"].i();
        std::ostringstream os;
        os << sum;
        return crow::response {os.str()};
    });

    CROW_ROUTE(app, "/params")([](const crow::request& req) {
        std::ostringstream os;
        os << "Params: " << req.url_params << "\n\n";
        os << "The key 'foo' was " << (req.url_params.get("foo") == nullptr ? "not " : "") << "found.\n";
        if(req.url_params.get("pew") != nullptr) {
            double countD = boost::lexical_cast<double>(req.url_params.get("pew"));
            os << "The value of 'pew' is " << countD << '\n';
        }
        auto count = req.url_params.get_list("count");
        os << "The key 'count' contains " << count.size() << " value(s).\n";
        for(const auto& countVal : count) {
            os << " - " << countVal << '\n';
        }
        return crow::response {os.str()};
    });

    // crow::Logger::setHandler(std::make_shared<ExampleLogHandler>());
    crow::logger::setLogLevel(crow::LogLevel::DEBUG);

    app.bindaddr("127.0.0.1").port(18080).multithreaded().run();

}



